programming4us
           
 
 
Programming

Adding iPad to the Mix

- Free product key for windows 10
- Free Product Key for Microsoft office 365
- Malwarebytes Premium 3.7.1 Serial Keys (LifeTime) 2019
11/13/2010 5:16:06 PM
Now we're ready to upgrade NavApp for the iPad. Before kicking off this process, make a backup copy of your project directory. This can be useful in case you want to compare your original app with the iPad-ready version that Xcode sets up.

Next, in the Groups & Files section of your Xcode project window, open the Targets section and select NavApp. Then select Project Upgrade Current Target for iPad from the menu. Xcode will present you with a modal sheet that asks whether you want to create a single universal application that will run on both iPhone and iPad, or create a second target for an iPad application in your project, leaving the original target intact. Select the One Universal application option, and then click OK.

Xcode now does a few simple things. It copies the MainWindow.xib file to MainWindow-iPad.xib, making a few changes to the file's contents, such as specifying the iPad's screen size. The new .xib file is added to the project, and a line is added to the NavAppCompare-Info.plist file, specifying that this new .xib file should be used when launching on the iPad. It also makes a few changes to your project, such as setting the base SDK to 3.2.

1. Taking the Upgraded NavApp for a Spin

Make sure that Simulator 3.2 is chosen as the Active SDK in Xcode, and then build and run the upgraded app. You should see NavApp spring to life, full size and at full resolution, in the Simulator. It will work just as it did in iPhone form, letting you drill down through the structure we laid out previously and displaying a similar result, as shown in Figure 1.

Figure 1. The ChoiceViewController GUI, running on the iPad

Although this type of upgrade works, it isn't what you really want for an iPad app. The popular iPhone pattern of drilling down into structures, with the entire content of the screen sliding out the side, isn't prevalent on the iPad. In fact, Apple actually recommends against that usage, for a couple of reasons:

  • The full-screen wipe in response to simple tap on the screen, which works well enough on a small display such as the iPhone's, begins to feel a little off on a larger screen. The full-screen swish is best reserved for situations where the user actually made a swiping gesture.

  • Since the iPad has so much more screen real estate, you can easily show a drill-down navigation view alongside of, or hovering in front of, the main content, by using a split view or a popover view (as you've seen in earlier chapters).

So, let's rethink the NavApp GUI for the iPad version.

Reconsidering iPhone Design ChoicesWhile the navigation views are the first things you see in NavApp, they're actually just stepping-stones leading to the app's main content view, which is handled by the ChoiceViewController class.

For the iPad version of this app, let's rework the design so that the final view is now front and center. We'll go about this by reconfiguring some .xib files, conditionally changing the behavior of the navigation views in response to user actions, and extending the ChoiceViewController class so that it can display something reasonable, even when the user hasn't selected anything yet. The navigation views will end up being displayed in the left-hand side of a split view, or in a floating popover view, depending on whether the iPad is in landscape or portrait mode. This is similar to what we did in the Dudel application earlier in this book, and even goes a step closer to the way that the iPad's built-in Mail application handles drilling down through accounts and folders to reach your messages.

The first step toward making this work will be to redefine what the NavAppAppDelegate class does, both in code and in its related .xib files. This class was created automatically when we created the Xcode project, and in its original form, it sets up the navigation interface (since that's the kind of project we created). We're going to add a bit of code that checks at runtime to see if we're running on an iPad, and if so, instead set up a split view interface. The other half of this redesign will be configuring the MainWindow-iPad.xib file so that it actually wraps things up in a split view.

2. Conditional Behavior: Know Your Idioms

Open NavAppAppDelegate.h, and add an outlet for a future UISplitViewController as shown here:

@interface NavAppAppDelegate : NSObject <UIApplicationDelegate> {
UIWindow *window;
UINavigationController *navigationController;
UISplitViewController *splitViewController;
}
@property (nonatomic, retain) IBOutlet UIWindow *window;
@property (nonatomic, retain) IBOutlet UINavigationController *navigationController;
@property (nonatomic, retain) IBOutlet UISplitViewController *splitViewController;
@end


NOTE

We're working with a class template that was generated by Xcode and contains its IBOutlet markers in the property declarations. Rather than modifying the generated source code to make a change that has no quantifiable effect, we're just following the example of the surrounding code here. When in Rome ...

Now switch over to NavAppAppDelegate.m, and configure the basics for the new outlet we created by adding this line near the top of the @implementation section:

@synthesize splitViewController;

Don't forget to free up that new resource as well:

- (void)dealloc {
[splitViewController release];
[navigationController release];
[window release];
[super dealloc];
}

Next is the interesting part of this class:

- (BOOL)application:(UIApplication *)application
didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad) {
[window addSubview:[splitViewController view]];
} else {
[window addSubview:[navigationController view]];
}
[window makeKeyAndVisible];
return YES;
}

This method uses the UI_USER_INTERFACE_IDIOM function to determine whether the app is running on an iPad. If it is, we'll present a different view than what we show for the iPhone.

This is a pretty subtle shift. Keep in mind that the app delegate class is loaded from the app's main .xib file, and once it's loaded and the application has finished launching, this is the method that actually gives the application a view to display. With this small change, we radically alter the entire appearance and flow of the app! Of course, to make that really happen, we'll need to make sure that our new splitViewController outlet is actually pointing at something.

3. Configuring the Main iPad GUI

It's time to reorganize the main GUI, putting the navigation view inside a split view. Open MainWindow-iPad.xib in Interface Builder, and switch the main window to column view, revealing something like Figure 2.

Figure 2. The primary .xib file for the iPad version of our app, before our enhancements

Here, we've drilled down into the Navigation Controller and Root View Controller objects, revealing the complete structure of the objects in this .xib file. If you select the Nav App App Delegate object in this window, and then open the connections inspector, you'll see that it has outlets connected to the window and to the navigation controller—the two objects that are tied together in code when the app launches—by virtue of adding the view controller's view to the window. We're going to add a UISplitViewController to this .xib file, and configure it so that the preceding conditional code adds the split view to the window.

Start by finding a UISplitViewController in the Library, and dragging it to the leftmost column of the .xib window. Then control-drag from the app delegate to the new split view controller, and hook up the splitViewController outlet.

The split view is meant to display views for two view controllers at once, and by default, the one we created will have a navigation controller and a generic view controller. The navigation controller contains a generic table view controller. We need to modify these objects, making them instances of the real classes we're using in our app.

Drill down into the Navigation Controller object inside the Split View Controller object, and select the Table View Controller object it contains. Open the identity inspector, and change that controller's class to RootViewController. Then switch to the attribute inspector to configure the controller a little more. Set the Title to Changes, and the NIB Name to RootViewController.

Now backtrack a bit, and select the generic View Controller object inside the Split View Controller object. Once again, bring up the identity inspector, and set this controller's class to ChoiceViewController

. Then switch back to the attribute inspector, and set the NIB Name to ChoiceViewController-iPad. That's the name of an .xib file that doesn't exist yet, but soon will, since we'll create it in the next section. At this point, your .xib window should look something like Figure 3.

Figure 3. The iPad version of the main .xib file after reconfiguring for iPad navigation

Proper use of a split view requires you to provide the split view controller with a delegate, which plays a role in juggling between a split view and a popover when the iPad is rotated. In this case, we'll connect the split view controller's delegate outlet to the choice view controller, and later we'll implement the delegate code there. Select the Split View Controller item so that you can see its children, control-drag from the Split View Controller object to the Choice View Controller object, and then connect the delegate outlet.

The final change for the MainWindow-iPad.xib file is to delete the navigation controller that's at the top level of the .xib file. The app delegate still has an outlet to it, but that doesn't really matter. When our app runs on an iPad, the iPad-specific .xib file is loaded, and the unconnected outlet is ignored.

4. Creating the Choice View Controller GUI for iPad

Earlier, we configured the ChoiceViewController instance in our main iPad GUI to use a special iPad-friendly .xib file. Let's create that now. Switch back to Xcode, and use the New File Assistant to create a new View XIB file, located in the iPhone OS / User Interface section. Make sure the product menu is displaying iPad, and click Next. Then name it ChoiceViewController-iPad.xib and click Next. You'll see the new file added to your project.

Before editing the new GUI, open ChoiceViewController.h and add the following instance variable:

IBOutlet UIToolbar *toolbar;

This new toolbar outlet will point at a toolbar in the iPad version of the GUI, which we'll create soon.

Open both ChoiceViewController.xib and ChoiceViewController-iPad.xib in Interface Builder. Unlike the original .xib file, which was created along with the class, the new one is kind of a blank slate. Select the File's Owner icon, and use the identity inspector to set its class to ChoiceViewController. Now switch to ChoiceViewController.xib, open its view, select all the GUI objects in there, and press C to copy them. Then switch back to the new ChoiceViewController-iPad.xib file, open its view (which you'll see is iPad-size), and paste in the GUI objects. You'll want to center them in the display, and should probably resize them to fill the width of the display as well—no sense letting all that screen real estate go to waste!

Now use the Library to find a UIToolbar, and drag it to the new iPad-ready ChoiceViewController view, dropping it at the top of the view so that the toolbar appears up there. The toolbar contains a single default item, which you should go ahead and delete. Finally, connect the outlets from the File's Owner icon to the GUI objects in the .xib file: choiceLabel to the big label in the middle, toolbar to the toolbar you just created, and view (which we didn't define in out class, but inherited from UIViewController) to the entire containing view.

5. Implementing the Split View Delegate Methods

Go back to Xcode, and open the ChoiceViewController.m file. Add the two required methods for the UISplitViewController:

- (void)splitViewController:(UISplitViewController*)svc
willHideViewController:(UIViewController *)aViewController
withBarButtonItem:(UIBarButtonItem*)barButtonItem
forPopoverController:(UIPopoverController*)pc {
// add the new button item to our toolbar
NSArray *newItems = [toolbar.items arrayByAddingObject:barButtonItem];
[toolbar setItems:newItems animated:YES];

// configure the button
barButtonItem.title = @"Choices";
}
- (void)splitViewController:(UISplitViewController*)svc
willShowViewController:(UIViewController *)aViewController
invalidatingBarButtonItem:(UIBarButtonItem *)button {
// remove the button
NSMutableArray *newItems = [[toolbar.items mutableCopy] autorelease];
if ([newItems containsObject:button]) {
[newItems removeObject:button];
[toolbar setItems:newItems animated:YES];
}
}

That's all we need to do in order to handle switching between portrait and landscape orientation. The split view controller will call the first method when switching to portrait mode, and the second method when switching to landscape mode.

At this point, you should be able to run the app. You'll see that it works ... to some extent. The split view kicks in, displaying itself on the left side in landscape mode, and shrinking down to a button in the toolbar in portrait mode. Rotating from one to another isn't working yet, but we'll get to that a little later.

The problem is in the interaction between the view controllers themselves. All the action—not only the navigation, but also the display of the final selection—is constrained to the navigation view, whether it's appearing in the split view or in a popover view. The big view for displaying the choice just displays the default "dummy" text all the time! Clearly, we need to update our table view controllers so that they do different things in response to the user selecting a row, depending on whether the app is running on an iPhone or iPad.

6. Tweaking the Navigation Logic

First, we need to make a pair of identical changes for both RootViewController.m and ChoiceViewController.m, to ensure that the views can rotate properly. In each of those files, uncomment the shouldAutorotateToInterfaceOrientation: method, and make it always return YES:

- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)o{
// Return YES for supported orientations.
return YES;
}

Now switch over to SecondLevelViewController.m, where we'll make some rather more critical changes. Start by adding this somewhere near the top of the file:

#import "NavAppAppDelegate.h"

Next, uncomment the shouldAutorotateToInterfaceOrientation: method, and make it always return YES, as we just did for the RootViewController and ChoiceViewController classes.

Then, in the tableView:cellForRowAtIndexPath: method, add a bit of code so that we don't show the final disclosure indicator (the little right-pointing arrow/chevron that lets the users know that they can keep on digging):

cell.textLabel.text = [NSString stringWithFormat:@"Sub-Item #%d", indexPath.row];
if (UI_USER_INTERFACE_IDIOM() != UIUserInterfaceIdiomPad) {
cell.accessoryType = UITableViewCellAccessoryDisclosureIndicator;
}


Then change the behavior of the final selection here, so that instead of creating and pushing another view controller onto the navigation stack, we grab the "global" ChoiceViewController and just tell it what the selection is:

- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {


if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad) {
NavAppAppDelegate *appDelegate =
[[UIApplication sharedApplication] delegate];
UISplitViewController *splitViewController =
appDelegate.splitViewController;
ChoiceViewController *detailViewController =
[splitViewController.viewControllers objectAtIndex:1];
detailViewController.choice = [NSString stringWithFormat:
@"%@, Sub-Item #%d", self.choice, indexPath.row];
} else {
ChoiceViewController *detailViewController = [[ChoiceViewController
alloc] initWithNibName:@"ChoiceViewController" bundle:nil];
detailViewController.choice = [NSString stringWithFormat:
@"%@, Sub-Item #%d", self.choice, indexPath.row];

// Pass the selected object to the new view controller.
[self.navigationController pushViewController:detailViewController
animated:YES];
[detailViewController release];
}
}

Now you should be able to build and run the app, and see something closer to what we're shooting for. You can pick an item and a subitem, and your choice is displayed in the main view (and not inside the navigation view). However, this is still a bit off. That main view is just showing default dummy values (whatever you entered in Interface Builder) until the user selects something, and that's not what we want.

Let's enhance ChoiceViewController a bit, so that we can display something special for the no-selection state, before the user has navigated anywhere.

7. Enhancing the Main View with a No-Selection State

Basically, the new no-selection state will consist of hiding the labels at the top and bottom, and putting a special text in the large center label.

Start by adding two new outlets to the class definition ChoiceViewController.h so that we can access the top and bottom labels:

IBOutlet UILabel *topLabel;
IBOutlet UILabel *bottomLabel;

Now open ChoiceViewController-iPad.xib, and connect each of the new outlets by control-dragging from File's Owner to each of the labels and selecting the proper outlet. Save your changes, and go back to Xcode.

NOTE

If you're worried about the fact that the new outlets won't be used in the non-iPad version of the GUI, don't be! When this code runs on an iPhone and the iPhone version of the GUI is loaded, those unconnected outlets will simply be left as pointers to nil—no harm done.

Open ChoiceViewController.m to make a few quick changes. The first changes will be for the viewWillAppear: method, to make it display the appropriate content depending on whether or not the choice property is populated:

- (void)viewWillAppear:(BOOL)animated {
[super viewWillAppear:animated];
if (self.choice) {
self.navigationItem.title = self.choice;
choiceLabel.text = choice;
topLabel.hidden = NO;
bottomLabel.hidden = NO;
} else {
choiceLabel.text = @"Make your choice!";
topLabel.hidden = YES;
bottomLabel.hidden = YES;
}
}

Next, we're going to implement the setChoice: method. So far, we've relied on the @synthesized version of this, but now that we need to update the display once the value is set, we should actually do something here.

- (void)setChoice:(NSString *)c {
if (![c isEqual:choice]) {
[choice release];
choice = [c copy];
self.navigationItem.title = self.choice;
choiceLabel.text = choice;
topLabel.hidden = NO;
bottomLabel.hidden = NO;
}
}

Note that we don't need to do anything here to handle the case where the new value for choice is nil (which would theoretically require us to once again put "Make your choice!" in the main label and hide the other labels), since in practice, this will never occur. The only time that choice is set is when the user has just selected something, and in this app, that "something" is never nil.

At this point, you should be able to run the app and see it working the way that we intended and that makes the most sense, without any surprises for the users. When you first launch the app, nothing is selected in the navigation view, and the main display reflects this. Once you select something, your selection sticks around in the main view until you navigate to something else. This is pretty much identical to the behavior of other iPad apps such as Mail, so users should feel right at home with another app that works this way.

Thanks to the way we've written the app, it should also continue to work on iPhone just as it used to. To launch your app on the Simulator in iPhone mode, the key is to build the app using the 3.2 target, then switch to the 3.1.3 (or other iPhone OS) target, and select Run Run from the menu.

Other -----------------
- A Brief History of Legacy .NET Distributed Technologies : .NET Remoting
- A Brief History of Legacy .NET Distributed Technologies : .NET Enterprise Services
- iPad SDK : Outputting to an External Screen
- iPad SDK : Displaying Multiple Videos
- Parallel Programming Drivers
- Parallel Programming with Microsoft .Net : Parallel Loops - An Example
- Parallel Programming with Microsoft .Net : Parallel Loops - The Basics
- What is New in iPhone SDK 3.2 for the iPad (part 2)
- What is New in iPhone SDK 3.2 for the iPad (part 1)
- Programming with DirectX : Rendering Geometry - Colors
- ASP.NET Security : The Membership and Role Management API (part 3) - Role
- ASP.NET Security : The Membership and Role Management API (part 2) - Provider
- ASP.NET Security : The Membership and Role Management API (part 1)
- ASP.NET Security : Security-Related Controls (part 2)
- ASP.NET Security : Security-Related Controls (part 1)
- WCF Security Concepts
- Certificate-Based Encryption
- Encryption Using SSL
- Security Privileges and Services
- Client Credentials
 
 
 
Top 10
 
- Microsoft Visio 2013 : Adding Structure to Your Diagrams - Finding containers and lists in Visio (part 2) - Wireframes,Legends
- Microsoft Visio 2013 : Adding Structure to Your Diagrams - Finding containers and lists in Visio (part 1) - Swimlanes
- Microsoft Visio 2013 : Adding Structure to Your Diagrams - Formatting and sizing lists
- Microsoft Visio 2013 : Adding Structure to Your Diagrams - Adding shapes to lists
- Microsoft Visio 2013 : Adding Structure to Your Diagrams - Sizing containers
- Microsoft Access 2010 : Control Properties and Why to Use Them (part 3) - The Other Properties of a Control
- Microsoft Access 2010 : Control Properties and Why to Use Them (part 2) - The Data Properties of a Control
- Microsoft Access 2010 : Control Properties and Why to Use Them (part 1) - The Format Properties of a Control
- Microsoft Access 2010 : Form Properties and Why Should You Use Them - Working with the Properties Window
- Microsoft Visio 2013 : Using the Organization Chart Wizard with new data
- First look: Apple Watch

- 3 Tips for Maintaining Your Cell Phone Battery (part 1)

- 3 Tips for Maintaining Your Cell Phone Battery (part 2)
programming4us programming4us